package aupdg.data.wrapper;

import aupdg.data.Log;
import aupdg.debug.LogReaderCreator;
import aupdg.logic.exceptions.LoopsException;
import aupdg.presentation.DataBean;
import java.util.*;
import org.processmining.framework.log.*;
import org.processmining.framework.log.classic.LogReaderClassic;
import org.processmining.framework.log.rfb.fsio.FS2VirtualFileSystem;
import org.processmining.framework.ui.menus.LogReaderMenu;
import org.processmining.framework.util.StopWatch;

/**
 * It is a wrapper of LogReader, the class used in ProM to load and read the
 * event log file in MXML format.
 *
 * @author AA and CJ
 */
public class ProMLog implements Log {

    private LogReader logReader;
    private List<ProcessInstance> instances;
    private ProcessInstance instance;
    private AuditTrailEntryList events;
    private AuditTrailEntry event;
    private Map<String, String> attributes;
    private Set<String> keySet;
    private String[] attrArray;
    private String attrKey;

    //public LogReader logReader1; //TODO change to private, logreader used to obtain data dependencies
    
    /**
     * The Constructor of ProMLog takes the databean object which contains the
     * file system's path of the log file and fills it with all the information
     * needed for the presentation layer. At the same time it initializes its 
     * fields.
     * @param dataBean
     * @throws Exception
     */
    public ProMLog(DataBean dataBean) throws Exception {
        int rowNum = 0;
        int attrEventCount = 0;
        ArrayList<Integer> eventKeys;
        ArrayList<Integer> inputAttr, outputAttr, otherAttr;

        // LogReaderFactory.setLogReaderClass(BufferedLogReader.class);
        LogReaderFactory.setLogReaderClass(LogReaderClassic.class);

        LogReaderMenu.storageProvider = FS2VirtualFileSystem.instance();
        FS2VirtualFileSystem.instance().setUseLazyCopies(true);

        // open log
        System.out.println("Loading log...");
        StopWatch timer = new StopWatch();
        timer.start();

        logReader = LogReaderCreator.openLog(dataBean.getPathToFile());
        timer.stop();
        System.out.println("Loaded log in " + timer.formatDuration());
        LogReaderCreator.reportMemory();
        System.out.println(logReader.numberOfProcesses());

        dataBean.setNumProcessInstances(logReader.numberOfInstances());
        dataBean.setNumLogEvents(logReader.getLogSummary().getLogEvents().size());

        dataBean.createLogTableData(logReader.getLogSummary().getNumberOfAuditTrailEntries(), 4);

        // set dataBean for logTable in logPanel
        dataBean.setNumTotalEvents(logReader.getLogSummary().getNumberOfAuditTrailEntries());
        dataBean.setnumOriginators(logReader.getLogSummary().getOriginators().length);

        //dataBean.initLogBrowser();

        dataBean.setLogReader(logReader);

        instances = logReader.getInstances();
        for (int i = 0; i < instances.size(); i++) {
            Map<String, String> loopsChecker = new HashMap();
            //instance
            instance = instances.get(i);
            events = instances.get(i).getAuditTrailEntryList();
            //dataBean.addInstanceKeyValue(i, instance.getName());
            eventKeys = new ArrayList<>();
            for (int j = 0; j < events.size(); j++) { //row
                //event
                event = events.get(j);
                attributes = event.getAttributes();

                //Checking presence of loops
                if (loopsChecker.containsKey(event.getName())) {
                    dataBean.setHasLoops(true);
                    throw new LoopsException();
                } else {
                    loopsChecker.put(event.getName(), null);
                }

                //dataBean.addEventKeyValue(rowNum, event.getName());
                eventKeys.add(rowNum);

                dataBean.setLogTableDataAt(0, rowNum, instance.getName()); //Instance
                dataBean.setLogTableDataAt(1, rowNum, event.getName()); //Event
                inputAttr = new ArrayList<>();
                outputAttr = new ArrayList<>();
                otherAttr = new ArrayList<>();
                //dataBean.addRowLogTableData(row);    
                for (int k = 0; k < attributes.size(); k++) {
                    attrEventCount += 1;
                    //eventAttributes
                    keySet = instances.get(i).getAuditTrailEntryList().get(j).getAttributes().keySet();
                    attrArray = (String[]) keySet.toArray(new String[keySet.size()]);

                    //for (int u=0; u<attrArray.length; u++){
                    attrKey = attrArray[k];
                    //TODO method substring produces java.lang.StringIndexOutOfBoundsException if
                    //length < 7
                    if (attrKey.length() > 6 && attrKey.substring(0, 6).equals("Input_")) {
                        if (dataBean.getLogTableDataAt(2, rowNum) == null || dataBean.getLogTableDataAt(2, rowNum).isEmpty()) {
                            dataBean.setLogTableDataAt(2, rowNum, attrKey.substring(6).toString());
                        } else {
                            dataBean.concatLogTableDataAt(2, rowNum, "," + attrKey.substring(6).toString());
                        }
                        //dataBean.addAttrInputKeyValue(attrEventCount, attrKey.substring(6).toString());
                        inputAttr.add(attrEventCount);

                    } else if (attrKey.length() > 7 && attrKey.substring(0, 7).equals("Output_")) {
                        if (dataBean.getLogTableDataAt(3, rowNum) == null || dataBean.getLogTableDataAt(3, rowNum).isEmpty()) {
                            dataBean.setLogTableDataAt(3, rowNum, attrKey.substring(7).toString());
                        } else {
                            dataBean.concatLogTableDataAt(3, rowNum, "," + attrKey.substring(7).toString());
                        }
                        //dataBean.addAttrOutputKeyValue(attrEventCount, attrKey.substring(7).toString());
                        outputAttr.add(attrEventCount);
                    } else {
                        //dataBean.addAttrOtherKeyValue(attrEventCount, attrKey.toString());
                        otherAttr.add(attrEventCount);
                    }
                }
                //}
                //dataBean.addMapEventAttrInputKeys(rowNum, inputAttr);
                //dataBean.addMapEventAttrOutputKeys(rowNum, outputAttr);
                //dataBean.addMapEventAttrOutputKeys(rowNum, otherAttr);
                rowNum += 1;
            }
            //dataBean.addMapInstanceEventKeys(i, eventKeys);
        }

        //dataBean.setLogTableDataAt(col, row, null);
    }

    @Override
    public Object getInnerLog() {
        return logReader;
    }
}
